package com.milepost.workflow.login;

import com.milepost.workflow.common.constant.MilepostConstant;
import com.milepost.workflow.common.enums.DsKeyEnum;
import com.milepost.workflow.config.dynamicDs.DataSourceContextHolder;
import com.milepost.workflow.response.Response;
import com.milepost.workflow.response.ResponseHelper;
import com.milepost.workflow.user.entity.UsersEntity;
import com.milepost.workflow.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

/**
 * @author huarf
 * @Description
 * @create 2022-04-08 22:22
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class LoginCtrl {

    private final UserService userService;

    /**
     * 登录接口，本地的登录和cas登录都走这个接口
     * <p>
     * cas登录流程如下：
     * 用户首先在浏览器上输入这个地址，http://localhost:8080/login/index.html
     * 然后会被cas拦截，跳转到cas登录页面，
     * 登录成功后回重定向到这个url，
     * 在这里能获取到cas放入session中的数据。
     * 通过cas放入session中的数据再次走一遍本地登录过程，
     *
     * @param response
     * @param httpSession
     * @return
     */
    @GetMapping("/login/index.html")
    public void login(HttpServletResponse response, HttpSession httpSession) {

        String redirectUrl = null;

        //登录失败的类型，1：cas没有回传用户数据；2：通过cas回传的用户名/工号没有查询到用户数据。
        int errorType = 0;

        try {

            //打印session中数据
            printSession(httpSession);

            Assertion assertion = (Assertion) httpSession.getAttribute("_const_cas_assertion_");
            //打印cas session
            printAssertion(assertion);

            if (assertion != null && assertion.getPrincipal() != null && assertion.getPrincipal().getName() != null) {
                DataSourceContextHolder.setDataSource(DsKeyEnum.USER.getKey());
                //用户在cas登录页面输入的用户名，就是工号，对应users.code和xlh_person.gh
                String loginName = assertion.getPrincipal().getName();
                log.info("cas回传登录用户：" + loginName);
                UsersEntity userEntity = userService.getByUserName(loginName);
                if (userEntity == null) {
                    errorType = 2;
                    throw new RuntimeException("通过cas回传的用户名/工号[" + loginName + "]没有查询到用户数据。");
                }
                //用户数据放入session中
                httpSession.setAttribute(MilepostConstant.USER_SESSION_KEY, userEntity);
                //重定向到服务首页
                redirectUrl = "/admin/index.html";
            } else {
                errorType = 1;
                throw new RuntimeException("cas没有回传用户数据。");
            }

        } catch (Exception e) {
            log.error("登录异常", e);
            redirectUrl = "/login/error.html?errorType=" + errorType;
        } finally {
            //必须清空，因为使用了SpringSession，非主库中没有SpringSession的表
            DataSourceContextHolder.clearDataSource();
            try {
                response.sendRedirect(redirectUrl);
            } catch (IOException e) {
                log.error("登录时重定向异常", e);
            }
        }
    }

    @GetMapping("/login/index1.html")
    public void login1(HttpServletRequest request, HttpServletResponse response, HttpSession httpSession) throws IOException {

        try {

            log.info("打印类型");
            log.info(request.getClass().toString());
            log.info(response.getClass().toString());
            log.info(httpSession.getClass().toString());
            log.info("打印类型");

            log.info("打印参数");
            log.info(request.getQueryString());
            Map<String, String[]> parameterMap = request.getParameterMap();
            for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                log.info(entry.getKey() + ":");
                for (String value : entry.getValue()) {
                    log.info("    " + value);
                }
            }
            log.info("打印参数");

            log.info("打印loginName");
            String loginName = (String) httpSession.getAttribute("cas.client.user");
            log.info(loginName);
            HttpSession session = request.getSession();
            log.info((String) session.getAttribute("cas.client.user"));
            log.info("打印loginName");

            log.info("打印session是否同源");
            log.info(httpSession.equals(session)+"");
            log.info("打印session是否同源");

            //打印session中数据
            printSession(httpSession);

        } catch (Exception e) {
            log.error("登录异常", e);
        } finally {
            //设置Content-Type
            response.setContentType("application/json;charset=UTF-8");
            //设置charset
            response.setCharacterEncoding("UTF-8");
            //写入
            PrintWriter writer = response.getWriter();
            writer.write("sadf");
        }
    }

    /**
     * 打印session中数据
     *
     * @param httpSession
     */
    private void printSession(HttpSession httpSession) {

        log.info("-------------------session begin");
        Enumeration<String> attributeNames = httpSession.getAttributeNames();
        while (attributeNames.hasMoreElements()) {
            String key = attributeNames.nextElement();
            Object attribute = httpSession.getAttribute(key);
            log.info(key + "=" + attribute);
        }
        log.info("-------------------session end");
    }

    /**
     * 打印cas session 中数据
     *
     * @param assertion
     */
    private void printAssertion(Assertion assertion) {

        log.info("-------------------cas session begin");

        if (assertion == null || assertion.getPrincipal() == null) {
            return;
        }
        //获得认证中心传过来的其它用户属性
        Map<String, Object> attributes = assertion.getPrincipal().getAttributes();

        if (attributes != null) {
            Iterator<String> iter = attributes.keySet().iterator();
            while (iter.hasNext()) {
                String key = iter.next();
                log.info(key + "=" + attributes.get(key));
            }
        }

        log.info("-------------------cas session end");
    }

    /**
     * 本地登录接口
     *
     * @param userName
     * @param pwd
     * @param httpSession
     * @return
     */
    @PostMapping("/login/local")
    public Response<UsersEntity> loginLocal(String userName, String pwd, HttpSession httpSession) {

        Response<UsersEntity> response = null;

        try {
            DataSourceContextHolder.setDataSource(DsKeyEnum.USER.getKey());
            UsersEntity userEntity = userService.getByUserNameAndPwd(userName, pwd);
            if (userEntity == null) {
                throw new RuntimeException("用户名或密码错误。");
            }
            //给登录接口返回数据
            response = ResponseHelper.createSuccessResponse(userEntity);
            //用户数据放入session中
            httpSession.setAttribute(MilepostConstant.USER_SESSION_KEY, userEntity);
        } catch (Exception e) {
            log.error("登录异常", e);
            response = ResponseHelper.createExceptionResponse(e);
        } finally {
            //必须清空，因为使用了SpringSession，非主库中没有SpringSession的表
            DataSourceContextHolder.clearDataSource();
        }

        return response;
    }

    /**
     * 登出
     *
     * @param httpSession
     * @return
     */
    @GetMapping("/logout")
    public Response<String> logout(HttpSession httpSession) {

        httpSession.removeAttribute(MilepostConstant.USER_SESSION_KEY);
        httpSession.invalidate();
        return ResponseHelper.createSuccessResponse();
    }

}
